﻿#include "process_data.h"
#include "exception.h"
class Vector;
class Matrix;
class MatrixObject;
class Scalar;

class Matrix
{
	friend class MatrixObject;
private:
	vector<vector<double> > data_list;
	int col_size;
	int row_size;

public:
	Matrix();
	Matrix(vector<vector<double> >& _data_list); // 행렬로 초기화
	Matrix(const Matrix& _matrix); // 복사 생성자
	Matrix(vector<double>& _data_list); // 열로 초기화
	Matrix(Vector& _vector); // 열 벡터로 초기화
	Matrix(int _row, int _col); // row * col 짜리 0 으로 초기화 된 행렬 생성

	// 행으로 초기화 하려면 is_row 에 true, 아니면 false
	Matrix(vector<double>& _data_list, bool is_row); 

	void swap_row(int i, int j); // i 행과 j 행을 뒤집는다 (0 행, 0 열 부터 시작!)
	void swap_col(int i, int j); // i 열과 j 열을 뒤집는다
	void copy_row(int from, int to); // from 행에서 to 행으로 복사한다.
	void copy_col(int from, int to); // from 열에서 to 열로 복사한다. (원래 데이터 보존)

	void move_row(int from, int to); // 이동시킨다. 이 때 원래 데이터는 사라진다. 
	void move_col(int from, int to);

	void resize(int row, int col); // row 행, col 열 행렬로 재조정 한다. 이 때 내용은 0 으로 초기화 된다.

	double element(int i, int j) const; // i 행, j 열의 원소를 얻어온다.

	double determinant(); // 행렬식 연산
	double det_opt(); // 최적화된 행렬식 연산 수행

	Vector column_Vector(int i); // i 열 벡터를 얻어온다.
	vector<double> column_vec(int i);
	
	int col() const { return col_size; } 
	int row() const { return row_size; }

	Matrix operator* (const Matrix &operand); // 행렬 곱
	Matrix operator* (const int scalar); // 스칼라 배

	Matrix operator+ (const Matrix &operand);
	void add_row(int to, int from, double times);
	Matrix operator- (Matrix &operand);
	Matrix& operator= (Matrix &operand);

	vector<double>& operator[] (int i);
	friend ostream& operator<< (ostream& os, const Matrix& matrix);
};

class Vector
{
protected:
	vector<double> data_list; // 열 벡터 이다.
	int _size; // 벡터 길이

public:
	Vector();
	Vector(const Vector& _vector);
	Vector(vector<double>& _data_list);
	
	double element (int i) const ; // i 번째 원소를 가져온다
	int size() { return _size; } // 벡터 크기를 구한다. 
	vector<double> get_data_list(); // 데이터 리스트 벡터를 리턴한다. 

	double operator[] (int i) { return data_list[i]; }
};

class Scalar
{
public:
	double data;
};
class MatrixObject : public Matrix
{
private:
	Matrix const* pMatrix; // 가리키고 있는 행렬
	int start_row, start_col;
	int end_row, end_col; // 시작 원소에서 끝나는 원소 까지

public:
	MatrixObject(Matrix const* _pMatrix) : Matrix(), pMatrix(_pMatrix) {}
	MatrixObject(Matrix const* _pointer, int _start_row, int _start_col, int _end_row, int _end_col);
	MatrixObject(MatrixObject const* _object);
	
	MatrixObject operator+ (MatrixObject& _object); // 주소값을 더한다. 

	void update(); // pMatrix 로 부터 데이터를 받는다. 
};